package com.jason.seckill.controller;


import com.alibaba.fastjson.JSON;
import com.jason.seckill.pojo.SeckillMessage;
import com.jason.seckill.pojo.SeckillOrder;
import com.jason.seckill.pojo.User;
import com.jason.seckill.rabbitmq.MQSender;
import com.jason.seckill.service.IGoodsService;
import com.jason.seckill.service.IOrderService;
import com.jason.seckill.service.ISeckillOrderService;
import com.jason.seckill.utils.RedisUtil;
import com.jason.seckill.vo.GoodsVo;
import com.jason.seckill.vo.RespBean;
import com.jason.seckill.vo.RespBeanEnum;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;


import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/seckill")
public class SeckillController implements InitializingBean {

    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private ISeckillOrderService seckillOrderService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MQSender mqSender;
    //@Autowired
    //private RedisScript<Long> script;
    //@Autowired
    //private RedisTemplate redisTemplate;
    private Map<Long, Boolean> emptyStockMap = new HashMap<>();

    //优化前 qps:389
    //第一次优化 qps:1396  但是此时还有超卖的风险
    //第二次优化后 qps:1139 解决了超卖的风险,qps降低了一点,因为多了访问数据库的操作以及数据库索引的绑定
    //第三次优化后 qps:2004   利用消息队列实现流量削峰和redis将库存暂存到缓存中进一步优化
    //第四次优化 qps:720 这是因为我们实现redis分布式锁的时候没在redis服务器上实现，而是从java程序发送过去的
    //而且分布式锁本身就是一件非常非常消耗资源的事情
    @PostMapping("/{path}/doSeckill")
    @ResponseBody
    public RespBean doSeckill(@PathVariable String path, User user, Long goodsId) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        //判断路径是否正确
        boolean check = orderService.checkPath(user, goodsId, path);
        if (!check) {
            return RespBean.error(RespBeanEnum.REQUEST_ILLEGAL);
        }
        //判断是否重复购买
        SeckillOrder seckillOrder = (SeckillOrder) redisUtil.get("order" + user.getId() + ":" + goodsId);
        if (seckillOrder != null) {
            return RespBean.error(RespBeanEnum.REPEATED_ERROR);
        }
        //这样可以让后续来的判断 都直接return出去 不往下走了,不然商品已经空了,还一直访问redis
        if (emptyStockMap.get(goodsId)) {
            return RespBean.error(RespBeanEnum.REPEATED_ERROR);
        }
        //递减库存
        long stock = redisUtil.decr("seckillGoods:" + goodsId);
        //分布式锁
        //Long stock = (Long) redisTemplate.execute(script, Collections.singletonList("seckillGoods:" + goodsId), Collections.EMPTY_LIST);
        if (stock < 0) {
            emptyStockMap.put(goodsId, true);
            //因为库存为0时，前面会变成-1进入这个if,所以这里最好给他加成0,不然-1不太好
            redisUtil.incr("seckillGoods:" + goodsId);
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        SeckillMessage seckillMessage = new SeckillMessage(user, goodsId);
        mqSender.sendSeckillMessage(JSON.toJSONString(seckillMessage));
        return RespBean.success(0);
    }

    //获取秒杀结果 orderid：成功 -1：失败  0:等待
    @GetMapping("/result")
    @ResponseBody
    public RespBean getResult(User user, Long goodsId) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        Long orderId = seckillOrderService.getResult(user, goodsId);
        return RespBean.success(orderId);
    }

    //
    @GetMapping("/path")
    @ResponseBody
    public RespBean getPath(User user, Long goodsId) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        //创建随机路径，用于真正秒杀的时候进行匹配
        String str = orderService.createPath(user, goodsId);
        return RespBean.success(str);
    }


    //把库存加载到redis 在spring初始化的时候会先执行这个
    //把商品库存加载到redis中去
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> list = goodsService.findGoodsVo();
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        list.forEach(goodsVo -> {
            redisUtil.set("seckillGoods:" + goodsVo.getId(), goodsVo.getStockCount());
            emptyStockMap.put(goodsVo.getId(), false);
        });
    }

    //@PostMapping("/doSeckill2")
    //@ResponseBody
    //public RespBean doSeckill2(Model model, User user,Long goodsId){
    //    if(user==null){
    //        return RespBean.error(RespBeanEnum.SESSION_ERROR);
    //    }
    //    GoodsVo goods = goodsService.findGoodsVoByGoodsId(goodsId);
    //    //判断库存
    //    if(goods.getStockCount()<1){
    //        return RespBean.error(RespBeanEnum.EMPTY_STOCK);
    //    }
    //    //判断是否重复购买
    //    SeckillOrder seckillOrder = (SeckillOrder) redisUtil.get("order" + user.getId() + ":" + goods.getId());
    //    if(seckillOrder!=null){
    //        return RespBean.error(RespBeanEnum.REPEATED_ERROR);
    //    }
    //    //下单
    //    Order order = orderService.seckill(user,goods);
    //    return RespBean.success(order);
    //}

    //@RequestMapping("/doSeckill3")
    //public String doSeckill3(Model model, User user,Long goodsId){
    //    if(user==null){
    //        return "login";
    //    }
    //    GoodsVo goods = goodsService.findGoodsVoByGoodsId(goodsId);
    //    //判断库存
    //    if(goods.getStockCount()<1){
    //        model.addAttribute("errmsg", RespBeanEnum.EMPTY_STOCK.getMessage());
    //        return "secKillFail";
    //    }
    //    //判断是否重复购买
    //    SeckillOrder seckillOrder = seckillOrderService.getOne(new QueryWrapper<SeckillOrder>()
    //            .eq("user_id", user.getId())
    //            .eq("goods_id", goodsId));
    //    if(seckillOrder!=null){
    //        model.addAttribute("errmsg",RespBeanEnum.REPEATED_ERROR.getMessage());
    //    }
    //    //下单
    //    Order order = orderService.seckill(user,goods);
    //
    //    model.addAttribute("order",order);
    //    model.addAttribute("goods",goods);
    //    model.addAttribute("user",user);
    //    return "orderDetail";
    //}
}
